package com.tianji.remark.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.learning.LearningClient;
import com.tianji.api.dto.LikedTimesDTO;
import com.tianji.api.vo.ReplyVO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.RedisConstant;
import com.tianji.common.exceptions.ForbiddenException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.remark.domain.dto.LikeRecordFormDTO;
import com.tianji.remark.domain.po.LikedRecord;
import com.tianji.remark.mapper.LikedRecordMapper;
import com.tianji.remark.service.ILikedRecordService;
import com.tianji.remark.service.ILikedStatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * TODO
 *
 * @Author whx
 * @Date 2025/1/3 20:07
 */
@Service
public class LikedRecordRedisServiceImpl extends ServiceImpl<LikedRecordMapper, LikedRecord> implements ILikedRecordService{

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RabbitMqHelper mqHelper;

    @Autowired
    private LearningClient learningClient;

    @Override
    public void like(LikeRecordFormDTO dto) {
        // 判断bizId是否存在
        ReplyVO bean = learningClient.getIRById(dto.getBizId());
        if(ObjectUtil.isNull(bean)){
            throw new ForbiddenException("该数据已被删除");
        }

        Long userId = UserContext.getUser();

        String key = RedisConstant.LIKE_BIZ_KEY_PREFIX + dto.getBizId();

        if(dto.getLiked()){
            // 点赞
            // 直接插入redis
            Long result = redisTemplate.opsForSet().add(key, userId.toString());
            if(result == 0){
                throw new ForbiddenException("您已经点过赞了");
            }

        }else {
            // 取消点赞
            Long result = redisTemplate.opsForSet().remove(key, userId.toString());
            if(result == 0){
                throw new ForbiddenException("您还未点赞，无法取消");
            }
        }

        // 统计数据
        Long likedTimes = redisTemplate.opsForSet().size(key);
        if (likedTimes == null) {
            return;
        }

        String ZSetKey = RedisConstant.LIKE_COUNT_KEY_PREFIX + dto.getBizType();

        // 插入统计缓存
        redisTemplate.opsForZSet().add(ZSetKey, dto.getBizId().toString(), likedTimes);

    }

    @Override
    public List<Long> likedBizList(List<Long> bizIds) {

        List<Object> bizIdsList = redisTemplate.executePipelined(new RedisCallback<List<Long>>() {
            @Override
            public List<Long> doInRedis(RedisConnection connection) throws DataAccessException {

                StringRedisConnection src = (StringRedisConnection) connection;

                List<Long> ids = new ArrayList<>();

                for (Long bizId : bizIds) {
                    String key = RedisConstant.LIKE_BIZ_KEY_PREFIX + bizId;

                    Boolean result = src.sIsMember(key, UserContext.getUser().toString());

                    if (result) {
                        ids.add(bizId);
                    }
                }

                return ids;
            }
        });

        return bizIdsList.stream().map(id->Long.valueOf(id.toString())).collect(Collectors.toList());
    }

    @Autowired
    private ILikedStatService likedStatService;

    @Override
    public void readLikedTimesAndSendMessage(String bizType, int maxBizSize) {
        // 1.读取并移除Redis中缓存的点赞总数
        String key = RedisConstant.LIKE_COUNT_KEY_PREFIX + bizType;
        Set<ZSetOperations.TypedTuple<String>> tuples = redisTemplate.opsForZSet().popMin(key, maxBizSize);
        if (CollUtils.isEmpty(tuples)) {
            return;
        }
        // 2.数据转换
        List<LikedTimesDTO> list = new ArrayList<>(tuples.size());
        for (ZSetOperations.TypedTuple<String> tuple : tuples) {
            String bizId = tuple.getValue();
            Double likedTimes = tuple.getScore();
            if (bizId == null || likedTimes == null) {
                continue;
            }
            list.add(LikedTimesDTO.of(Long.valueOf(bizId), likedTimes.intValue()));
        }
        // 3.批量修改点赞数量
        likedStatService.updateLikedTimes(bizType, list);
    }


}
